﻿using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace SingleBlog.UI.Controls
{
    public static class PaginationExtensions
    {
        public static IHtmlContent Pagination<T>(this IHtmlHelper htmlHelper, PagedCollection<T> collection, PageButtonOptions options = default(PageButtonOptions))
        {

            if (options == null)
            {
                options = new PageButtonOptions();
            }

            if (collection.Count == 0 || collection.ItemsPerPage == 0)
            {
                return HtmlString.Empty;
            }
            var totalPages = collection.TotalPages;
            //未超过一页时不显示分页按钮
            if (!options.AlwaysShow && totalPages <= 1)
            {
                return HtmlString.Empty;
            }

            var pageIndex = collection.CurrentPage;

            bool showNumberic = false;
            bool showFirst = false;
            bool showLast = false;
            bool showPrevious = false;
            bool showNext = false;
            var mode = options.ButtonMode;
            if (mode == PageButtonMode.FirstLastNumberic || mode == PageButtonMode.PreviousNextFirstLastNumberic || mode == PageButtonMode.PreviousNextNumberic || mode == PageButtonMode.OnlyNumberic)
            {
                showNumberic = true;
            }

            if (mode == PageButtonMode.FirstLastNumberic || mode == PageButtonMode.PreviousNextFirstLast || mode == PageButtonMode.PreviousNextFirstLastNumberic)
            {
                showFirst = true;
                showLast = true;
            }

            if (mode == PageButtonMode.PreviousNext || mode == PageButtonMode.PreviousNextFirstLast || mode == PageButtonMode.PreviousNextFirstLastNumberic || mode == PageButtonMode.PreviousNextNumberic)
            {
                showPrevious = true;
                showNext = true;
            }

            string firstText = options.TextOfFirst;
            string previouseText = options.TextOfPrevious;
            string nextText = options.TextOfNext;
            string lastText = options.TextOfLast;

            //分页字符串
            TagBuilder pageBuilder = new TagBuilder("ul");

            pageBuilder.AddCssClass("pagination");

            pageBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(options.HtmlAttributes));

            if (showFirst)
            {
                htmlHelper.GeneratePageButton(pageBuilder, pageIndex <= 1, 1, firstText, options);
            }

            if (showPrevious)
            {
                htmlHelper.GeneratePageButton(pageBuilder, pageIndex - 1 < 1, pageIndex - 1, previouseText, options);
            }

            #region 计算页数

            if (showNumberic)
            {
                long startPage = 1;
                long endPage = 1;
                int numbericCount = options.NumbericCount;
                if (totalPages > numbericCount)
                {
                    if (pageIndex - (numbericCount / 2) > 0)
                    {
                        if (pageIndex + (numbericCount / 2) < totalPages)
                        {
                            startPage = pageIndex - (numbericCount / 2);
                            endPage = startPage + numbericCount - 1;
                        }
                        else
                        {
                            endPage = totalPages;
                            startPage = endPage - numbericCount + 1;
                        }
                    }
                    else
                    {
                        endPage = numbericCount;
                    }
                }
                else
                {
                    startPage = 1;
                    endPage = totalPages;
                }

                for (var i = startPage; i <= endPage; i++)
                {
                    htmlHelper.GeneratePageButton(pageBuilder, i == collection.CurrentPage, i, i.ToString(), options, i == collection.CurrentPage);
                }
            }
            #endregion

            if (showNext)
            {
                htmlHelper.GeneratePageButton(pageBuilder, pageIndex + 1 > totalPages, pageIndex + 1, nextText, options);
            }

            if (showLast)
            {
                htmlHelper.GeneratePageButton(pageBuilder, pageIndex >= totalPages, totalPages, lastText, options);
            }
            return pageBuilder;
        }

        /// <summary>
        /// 生成分页链接Url
        /// </summary>
        /// <param name="htmlHelper">HtmlHelper</param>
        /// <param name="page">页码</param>
        /// <param name="options">配置</param>
        /// <returns></returns>
        internal static string GeneratePaginationUrl(this IHtmlHelper htmlHelper, long page, PageButtonOptions options)
        {
            var currentUrl = htmlHelper.ViewContext.HttpContext.Request.Path.Value;

            if (currentUrl.IndexOf("?") == -1)
            {
                return string.Format("{0}?page={1}", currentUrl, page);
            }

            if (currentUrl.IndexOf("page=", StringComparison.InvariantCultureIgnoreCase) == -1)
            {
                return string.Format("{0}&page={1}", currentUrl, page);
            }
            return Regex.Replace(currentUrl, @"page=(\d+\.?\d*|\.\d+)", $"page={page}", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }

        internal static void GeneratePageButton(this IHtmlHelper htmlHelper,
   TagBuilder pageBuilder,
   bool canClick, long page, string text, PageButtonOptions options, bool current = false)
        {
            TagBuilder liTag = new TagBuilder("li");
            liTag.AddCssClass("page-item");
            if (canClick)
            {
                if (current)
                {
                    liTag.AddCssClass("active");
                }
                else
                {
                    liTag.AddCssClass("disabled");
                }
                liTag.InnerHtml.AppendHtml($"<span class='page-link'>{text}</span>");
            }
            else
            {
                liTag.InnerHtml.AppendHtml(string.Format("<a  class='page-link' href='{0}'>{1}</a>", htmlHelper.GeneratePaginationUrl(page, options), text));
            }

            pageBuilder.InnerHtml.AppendHtml(liTag);
        }
    }


    /// <summary>
    /// 分页按钮控件配置。
    /// </summary>
    public class PageButtonOptions
    {
        /// <summary>
        /// 初始化 <see cref="PageButtonOptions"/> 类的新实例。
        /// </summary>
        public PageButtonOptions()
        {
            //this.NumbericCount = 10;
            // this.AlwaysShow = true;
            //this.ButtonMode = PageButtonMode.PreviousNextFirstLastNumberic;
            ////this.ContainerTag = "ul";
        }
        /// <summary>
        /// 获取或设置分页显示的数字的数目。若设置为3，表示在中间的数字数目只显示近3页的数字；例如这样的形式：首页 上一页 2 3 4 下一页 末页。
        /// </summary>
        public int NumbericCount { get; set; } = 10;
        /// <summary>
        /// 获取或设置分页按钮是否一直显示。若为 true，当第一页的数据没有达到所需要分页的数据量时，分页组件将一直显示。否则，直到数据可以分页时才显示。
        /// </summary>
        public bool AlwaysShow { get; set; } = true;
        /// <summary>
        /// 获取或设置分页按钮显示的模式。
        /// </summary>
        public PageButtonMode ButtonMode { get; set; } = PageButtonMode.PreviousNextNumberic;

        /// <summary>
        /// 获取或设置“首页”的文本，支持 HTML 文本。
        /// </summary>
        public string TextOfFirst { get; set; } = "首页";

        /// <summary>
        /// 获取或设置“上一页”的文本，支持 HTML 文本。
        /// </summary>
        public string TextOfPrevious { get; set; } = "上一页";

        /// <summary>
        /// 获取或设置“下一页”的文本，支持 HTML 文本。
        /// </summary>
        public string TextOfNext { get; set; } = "下一页";

        /// <summary>
        /// 获取或设置“末页”的文本，支持 HTML 文本。
        /// </summary>
        public string TextOfLast { get; set; } = "末页";

        /// <summary>
        /// 获取或设置一个对象，其中包含要为该元素设置的 HTML 特性。
        /// </summary>
        public object HtmlAttributes { get; set; }

        /// <summary>
        /// 获取或设置路由名称。
        /// </summary>
        public string RouteName { get; set; }
        /// <summary>
        /// 获取或设置控制器名称。
        /// </summary>
        public string ControllerName { get; set; }
        /// <summary>
        /// 获取或设置行为名称。
        /// </summary>
        public string ActionName { get; set; }
    }

    /// <summary>
    /// 分页按钮模式
    /// </summary>
    public enum PageButtonMode
    {
        /// <summary>
        /// 上一页，下一页
        /// </summary>
        PreviousNext,
        /// <summary>
        /// 上一页，下一页，分页数字
        /// </summary>
        PreviousNextNumberic,
        /// <summary>
        /// 上一页，下一页，首页，末页
        /// </summary>
        PreviousNextFirstLast,
        /// <summary>
        /// 首页，末页，分页数字
        /// </summary>
        FirstLastNumberic,
        /// <summary>
        /// 上一页，下一页，首页，末页，分页数字
        /// </summary>
        PreviousNextFirstLastNumberic,
        /// <summary>
        /// 只显示数字
        /// </summary>
        OnlyNumberic,
    }
}
